package audio;


import java.io.IOException;
import java.io.PrintWriter;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

import java.net.Socket;

public class AudioSintetizado extends AudioBase 
{
	private static final long serialVersionUID = 1;

	static private AudioSintetizado instancia = null;

	private Socket socket;
	private PrintWriter outChannel;
	private BufferedReader inChannel;
	
	private String strSaida;
	
	private int contaPausa;
	
	private AudioSintetizado()
	{
		super();
		
		whoIAm = "SINTETIZADOR";
		
		socket = null;
		strSaida = "";
		inChannel = null;
		outChannel = null;
		estado = DESCONECTADO;
		
		contaPausa = 0;
	}
	
	static public AudioSintetizado instancia()
	{
		if ( instancia == null )
		{
			instancia = new AudioSintetizado();
		}
		
		return instancia;
	}
	
	private void aguardaCanal() throws AudioException
	{
		try 
		{
			while (!inChannel.ready()) 
			{
					Thread.sleep(200);
			}
		}
		catch ( Exception e) 
		{
			estado = PARADO;
			throw new AudioException(e.getMessage());
		}
	}
	
	public void iniciarSintetizador( boolean isWindows ) throws AudioException
	{
		String msg;
		
		try 
		{
			socket = new Socket("localhost", 1955);
			inChannel = new BufferedReader(
					new InputStreamReader(socket.getInputStream()));
			outChannel = new PrintWriter(
					new OutputStreamWriter(socket.getOutputStream()), true);
	
			aguardaCanal();

			msg = inChannel.readLine();
			
			System.out.println(msg);
		}
		catch ( IOException e ) 
		{
			estado = PARADO;
			throw new AudioException(e.getMessage());
		}
		
		if ( isWindows )
		{
			outChannel.println("~R 220");
			outChannel.println("~P 110");
			outChannel.println("~S 5 5");
			outChannel.println("~U 1");
		}
		else
		{
			outChannel.println("~R 1");
			outChannel.println("~P 0");
		}

		estado = PARADO;
	}
	
	public void escreve(String str)
	{
		
		if ( estado != DESCONECTADO )
		{
			char ultimo;
			
			// Elimina os brancos do início e do fim da frase.
			strSaida = str.trim();
			
			if ( strSaida.length() > 0 )
			{
				// Obtem o último caracter do cabeçalho
				ultimo = strSaida.charAt(strSaida.length() - 1);
				
				// Acrescenta um ponto no final da frase para melhorar a prosódia.
				if ( ".,!?;:".indexOf(ultimo) == -1 )
					strSaida += ".";
			}

			estado = TOCAR;
			System.out.println("ESTADO = " + estado + " - STR = " + strSaida);			
		}
	}
	
	@Override
	public void abortar() 
	{
		if ( estado != DESCONECTADO )
		{
			outChannel.println("~B");
			estado = PARADO;

			System.out.println("Aborta fala" );
		}
	}
	
	public void fechar()
	{
		System.out.println( "FECHAR " + estado );
		if ( estado != DESCONECTADO )
		{
			outChannel.println("~B");
			outChannel.println("~Q");

			estado = PARADO;

			System.out.println("Fechar" );
		}
	}
	
	public void encerrar()
	{
		System.out.println("Mandei encerrar" );
		fechar();
		estado = ENCERRAR;
	}

	protected void estadoIniciar()
	{
	}

	protected void estadoTocar()
	{
		System.out.println("Escrevi -> " + strSaida);

		/*
		 * Evita problemas se o loop da Thread foi interrompido 
		 *    entre o case e a chamada desta função
		 */
		if ( estado != TOCAR )
			return;

		outChannel.println(strSaida);

		contaPausa = 5;
		
		System.out.println("Sleep -> " + strSaida.length() * 75);

		strSaida = "";

		estado = TESTAR;
	}
	
	private boolean terminouFala() throws AudioException
	{
		if ( estado != DESCONECTADO )
		{
			String terminou;
			
			outChannel.println("~I");
			
			aguardaCanal();
			
			try 
			{
				terminou = inChannel.readLine();

				estado = TESTAR;

				System.out.println( "Terminou Fala -> " + terminou );
				
				return terminou.equals("0");
			}
			catch ( IOException e ) 
			{
				System.out.println( "Terminou Fala (Deu caca) " + e.getMessage() );
				estado = PARADO;
				throw new AudioException(e.getMessage());
			}
		}

		return true;
	}

	protected void estadoTestar() throws AudioException
	{
		/*
		 * Evita problemas se o loop da Thread foi interrompido 
		 *    entre o case e a chamada desta função
		 */
		if ( estado != TESTAR )
			return;

		if ( terminouFala() )
		{
			if ( --contaPausa == 0 )
			{	
				estado = PARADO;
				mandaEventoSilencio();
			}
		}
	}
}
